//
//  Func_iOS.m
//  Demo
//
//  Created by migame on 15/12/14.
//
//

#include "DownLoadCenter.h"
//#import "XMLReader.h"
#include <thread>
#include "Func_ios.h"


using namespace cocos2d::network;







static DownLoadCenter *one = nullptr;
DownLoadCenter *DownLoadCenter::getInstance()
{
    if( one == nullptr ){
        one = DownLoadCenter::create();
        one->retain();
    }
    return one;
}


bool DownLoadCenter::init()
{
    if( Node::init()==false ) return false;
    // 先确认路径的存在。
    if( FileUtils::getInstance()->isDirectoryExist(PATH_ALL)==false ){
        FileUtils::getInstance()->createDirectory(PATH_ALL);
        FileUtils::getInstance()->createDirectory(PATH_INFO_ALL);
        FileUtils::getInstance()->createDirectory(PATH_IMAGE_ALL);
    }
    // 初始化
    m_webName = WEB_69; // 默认就是69bobo
    oneTaskFinishedCallBack = nullptr;
    m_updateEvent = nullptr;
    m_allTaskNum = 0;
    m_downWebIndex = 0;
    m_readyTask_cache = MyArray::create();
    m_addTask_cache = MyArray::create();           // 网页任务添加池
    m_fixTask_cache = MyArray::create();            // 要修改的
    m_allDic = MyDictionary::create();             // 总数据存储字典。
    m_downOk_cache = MyDictionary::create();       // 下载成功后临时存储字典。
    m_sonThread_CMD = CMD_WAIT;                    // 子线程任务命令，在主线程中设置。
    m_sonThread_state = false;
    // 创建下载队列。
    for(int i=0;i<N_WEB_TASK;i++)
    {
        HttpNode *hn = HttpNode::create();
        hn->retain();
        m_taskHttpAry[i] = hn;
    }
    return true;
}


void DownLoadCenter::setWebName(std::string web){
    m_webName = web;
}

std::string DownLoadCenter::getNowWebName(){
    return m_webName;
}


int DownLoadCenter::getAllTaskNumber(){
    return m_allTaskNum;
}



void DownLoadCenter::setUpdateEvent(std::function<void(int allTasks, int finishedTasks )> evt){
    m_updateEvent = evt;
}


// 很重要。网站标示。
void DownLoadCenter::setNowWebName(std::string name){
    m_webName = name;
}


void DownLoadCenter::addWebTasK(std::string taskURL)
{
    if( m_addTask_cache )
    {
        __String *url = __String::createWithFormat("%s", taskURL.c_str() );
        m_addTask_cache->addObject( url );
    }
}




void DownLoadCenter::setOneTaskFinishCallBack(std::function<void(int taskId, std::string &taskURL, OneTaskInfo &info)> func){
    oneTaskFinishedCallBack = func;
}



void DownLoadCenter::startRun(){
    if( this->getParent()==nullptr )
        Director::getInstance()->getRunningScene()->addChild(this);
    // 每3秒检查更新
    this->schedule([this](float f){
        this->autoRunWebTask();
    }, 0.5, "connect web");
    // 每15秒，检查保存。
    this->schedule([this](float f){
    }, 4, "save web info");
    // 启动子线程。
    m_sonThread_state = SON_RUNNING;
    m_sonThread_CMD = CMD_READ;
    std::thread th( &DownLoadCenter::sonThreadFunc, this );
    th.detach();
}








// 主线程
void DownLoadCenter::autoRunWebTask()
{
    // 只有当子线程休眠时，才做主线程的事情。
    if(m_sonThread_state==SON_WAITING){
        Func_ios::Log(" start Main Thread 1: 获取临时任务缓存");
        autoGetSomeTaskFromCache();
        Func_ios::Log(" start Main Thread 2: 持续开始下载任务");
        continueWebTask();
        Func_ios::Log(" Main thread 1 2 ok");

        // 让子线程轮流进入 读－写状态。
        if( m_sonThread_CMD==CMD_WAIT )
            m_sonThread_CMD = CMD_READ;
        // 开启子线程。
        m_sonThread_state = SON_RUNNING;
    }
}


// 子线程。
void DownLoadCenter::sonThreadFunc()
{
    for(int i=1;i>0;i++)
    {
        if(i>10000000) i=1;
//        NSLog(@"当前是第[%d]次线程执行。", i);
        //----- 正事
        if( m_sonThread_state==SON_RUNNING )
        {
/////////////////////////////////////////////////////

            getPlistInfo_sonThread();
            saveInfo_sonThread();
/////////////////////////////////////////////////////
        }
        m_sonThread_state = SON_WAITING;
    }
}



void DownLoadCenter::autoGetSomeTaskFromCache()
{
    // 将预先添加的心任务，进行数据格式化后，记录进入 allDic。
    for(int i=0;i<m_addTask_cache->count() && i<N_Insert_Add_Task;i++)
    {
        __Dictionary *oneAddedUrlInfo = (__Dictionary*)m_addTask_cache->getObjectAtIndex(0);
        __String *taskURL = (__String *)oneAddedUrlInfo->objectForKey(INFO_ONE_WebURL);
        if( m_allDic->objectForKey( taskURL->getCString())==nullptr )
        {
            int taskId = m_allTaskNum;
            __Dictionary *oneInfo = __Dictionary::create();
            oneInfo->setObject( taskURL, INFO_ONE_WebURL);
            oneInfo->setObject(__String::createWithFormat("%s", "下载未完成" ),  INFO_ONE_TITLE);
            oneInfo->setObject(__String::createWithFormat("%s", "未分类" ),  INFO_ONE_BELONG );
            oneInfo->setObject(__String::createWithFormat("%d", 0 ),  INFO_ONE_IMG_NUMBER );
            oneInfo->setObject(__String::createWithFormat("%d", taskId ), INFO_ONE_ID);
            oneInfo->setObject(__String::createWithFormat("%s", TASK_STATE_wait ), INFO_ONE_STATE);
            oneInfo->setObject(__Array::create(), INFO_ONE_IMG_ARY);
            // 只能通过ID寻找，同时可以通过 url 和 taskID 寻找一条信息。
            m_allDic->setObject(oneInfo, __String::createWithFormat("%d", taskId)->getCString() );
            m_allDic->setObject(__String::createWithFormat("%d", taskId ), taskURL->getCString() );
            // 总数自增。
            m_allTaskNum ++;
            // 删除记录。
            m_addTask_cache->removeObject(oneAddedUrlInfo);
        }
        else{
            // 删除记录。
            m_addTask_cache->removeObject(oneAddedUrlInfo);
        }
    }

    // 将下载完成后的 dic 存入 allDic。
    for(int i=0;i<m_downOk_cache->count() && i<N_Change_OK_Task;i++)
    {
        __Dictionary *oneInfo = (__Dictionary*)m_downOk_cache->randomObject();
        __String *taskID = (__String *)oneInfo->objectForKey( INFO_ONE_ID );
        __String *taskURL = (__String *)oneInfo->objectForKey( INFO_ONE_WebURL );
        if( m_allDic->objectForKey( taskID->getCString())!=nullptr )
        {
            m_allDic->setObject(oneInfo, taskID->getCString());
            m_allDic->setObject(taskID, taskURL->getCString());
            // 删除该数据条目。
            m_downOk_cache->removeObjectForKey(taskID->getCString());
        }
        else{
            // 删除该数据条目。
            log(" 有一条没有记录但是又下载了的数据： id=%s, url=%s ", taskID->getCString(), taskURL->getCString() );
            m_downOk_cache->removeObjectForKey(taskID->getCString());
        }
    }

    // 从当前所在web的总dic中，抽取几个，添加到下载准备队列。
    if( m_readyTask_cache->count()<100 )
    {
        int nowAt = 0;
        for(int i=0;i<5;i++ )
        {
            for(;nowAt<m_allTaskNum; nowAt++)
            {
                __String *checkTask = __String::createWithFormat("%d", nowAt);
                __Dictionary *oneInfo = (__Dictionary *)m_allDic->objectForKey( checkTask->getCString());
                __String *state = nullptr;
                if( oneInfo )
                {
                    state = (__String*)oneInfo->objectForKey(INFO_ONE_STATE);
                    if( state->intValue()==STATE_wait )
                    {
                        OneTaskInfo one = OneTaskInfo::getFromDic(oneInfo);
                        m_readyTask_cache->addObject( one.getDic() );
                    }
                    break;
                }
            }
        }
    }
}



void DownLoadCenter::continueWebTask()
{
    // 任务按顺序下载。
    for(int i=0;i<N_WEB_TASK;i++)
    {
        HttpNode *hn = m_taskHttpAry[i];
        if(hn->isBusying()==true) continue;
        m_downWebIndex %= m_readyTask_cache->count();
        for(int i=m_downWebIndex;i<m_readyTask_cache->count();i++)
        {
            __Dictionary *oneInfo = (__Dictionary *)m_readyTask_cache->getObjectAtIndex(i);
            OneTaskInfo one = OneTaskInfo::getFromDic(oneInfo);
            int res = one.state.compare(TASK_STATE_wait);
            if( res==0 ){
                m_downWebIndex ++;
                hn->downWeb( one.url, one.taskId);
                break;
            }
        }
    }
}



void DownLoadCenter::getPlistInfo_sonThread()
{
    m_allDic->removeAllObjects();
    // 以后要加这个，可能还要多释放一次。
    std::string filePath = DownLoadCenter::getInfoFilePathByName(m_webName);
    MyDictionary *dic = MyDictionary::createWithContentsOfFile(filePath.c_str());
    if( dic!=nullptr )
        m_allDic = dic;
    NSLog(@" 全局字典已经取到了: %d个元素   [path: %s ]", m_allDic->count(), filePath.c_str() );
}




void DownLoadCenter::saveInfo_sonThread()
{
    Func_ios::Log(" 开始保存 当前使用的 save-plist ");
    std::string nowPlistPath = DownLoadCenter::getInfoFilePathByName(m_webName);
    if( m_allDic->writeToFile(nowPlistPath.c_str()) )
        log(" plist [%s] 保存成功", nowPlistPath.c_str() );
    else
        log(" plist 保存失败");
}





void DownLoadCenter::oneTaskDownLoadFinish(int taskId, std::string taskURL, OneTaskInfo backInfo )
{
    // 取回 对应的Dictionary，设置信息，并保存。
    MyDictionary *oneInfo = MyDictionary::create();
    oneInfo->setObject(MyString::createWithFormat("%s", backInfo.title.c_str() ),  INFO_ONE_TITLE);
    oneInfo->setObject(MyString::createWithFormat("%d", backInfo.imgNumber ),  INFO_ONE_IMG_NUMBER );
    oneInfo->setObject(MyString::createWithFormat("%s", backInfo.state.c_str() ), INFO_ONE_STATE);
    oneInfo->setObject(backInfo.ary_img, INFO_ONE_IMG_ARY);
    // 回调方法.
    OneTaskInfo one = backInfo;
    if( oneTaskFinishedCallBack )
        oneTaskFinishedCallBack( taskId, taskURL, one );
}






void DownLoadCenter::oneImageDownLoadFail(int taskId,  OneImageDownInfo *imgInfo)
{
    // 清理这个图片队列中的不能下载的图片。 但是这个清理要考虑到主线程池里的问题。
//    MyDictionary *oneInfo = (__Dictionary *)m_allDic->objectForKey( __String::createWithFormat("%d", taskId)->getCString() );
//    if( oneInfo )
//    {
//        __Array *imgAry = (__Array *)oneInfo->objectForKey(INFO_ONE_IMG_ARY);
//        if(imgAry->count()>imgInfo->inTaskIdx && ((__String*)imgAry->getObjectAtIndex(imgInfo->inTaskIdx))->compare(imgInfo->imgURL.c_str())==0)
//            imgAry->removeObjectAtIndex(imgInfo->inTaskIdx);
//        oneInfo->setObject( __String::createWithFormat("%ld", imgAry->count()), INFO_ONE_IMG_NUMBER);
//        if( imgAry->count()==0 )
//            oneInfo->setObject(__String::createWithFormat("%s", TASK_STATE_fail), INFO_ONE_STATE);
//    }
}




void DownLoadCenter::loadDataToArray(__Array *ary)
{
    // 确保在主线程执行，子线程休眠时使用。
    if( m_sonThread_state==SON_RUNNING )
        return ;
    for(int i=0;i<m_allTaskNum;i++)
    {
        MyDictionary *oneInfo = (MyDictionary *)m_allDic->objectForKey( __String::createWithFormat("%d",i)->getCString() );
        if(oneInfo==nullptr) continue;
        __String *state = (__String *)oneInfo->objectForKey(INFO_ONE_STATE);
        if( state->compare(TASK_STATE_ok)==0 )
        {
            ary->addObject(oneInfo);
        }
    }
}











std::string DownLoadCenter::getInfoFilePathByName(std::string name)
{
    std::string fileName = "";
    if( name=="69bobo" )
        fileName = "taskInfo_69bobo.plist";
    return PATH_INFO_ALL + fileName;
}




std::string DownLoadCenter::getImgDocPath( std::string webName ,int taskId){
    std::string docName = "";
    if( webName=="69bobo")
        docName = docName + "69bobo_" + __String::createWithFormat("%d", taskId)->getCString();
    return PATH_IMAGE_ALL + docName + "/";
}


std::string DownLoadCenter::getImgFilePath( std::string webName , int taskId, int index){
    return DownLoadCenter::getImgDocPath( webName , taskId) + __String::createWithFormat("%d",index)->getCString();
}



// 根据不同网站名，和taskID，获取对应目录文件夹。
std::string DownLoadCenter::getNowWebImgDocPath(int taskId)
{
    std::string wName = DownLoadCenter::getInstance()->getNowWebName();
    return DownLoadCenter::getImgDocPath(wName, taskId);
}


// 根据不同网站名，和taskID，获取对应目录文件夹。
std::string DownLoadCenter::getNowWebImgFilePath( int taskId, int index)
{
    std::string wName = DownLoadCenter::getInstance()->getNowWebName();
    return DownLoadCenter::getImgFilePath(wName, taskId, index);
}

















    